/*jslint sloppy: true */
/*global module, require */
var typeMap = {
		0x00: 'call',
		0x01: 'return',
		0x02: 'exit',
		0x11: 'wait',
		0x12: 'trigger',
		0x13: 'assert',
		0x14: 'jumpto',
		0x15: 'refresh'
	},
	logKeyMappping = {
		0x00: ['@type', 'processName'],
		0x01: ['@type'],
		0x02: ['@type', 'isPassed'],

		0x11: ['@type', 'delay'],
		0x12: ['type', 'isPassed', 'object', '@action', 'param'],
		0x13: ['@type', 'isPassed'],
		0x14: ['@type', 'url'],
		0x15: ['@type']
	},
	forEach = require('./util').forEach,
    isNumber = require('./util').isNumber,
	map = {F: 0, P: 1};

module.exports = function parseLog(logRawOpts) {
	var logList = [],
		logGroupByLoop = [],
		startLogNumber = 0,
		baseTime = logRawOpts.baseTime,
		availLineOptions = {},
		availLines = [],
		loopState = [[], []],
		performance = {};

	forEach(logRawOpts.performance, function (d, key) {
		performance[key] = {
			avg: NaN,
			min: NaN,
			max: NaN,
			data: []
		};
	});

	// Build logRaw into logObj style.
	forEach(logRawOpts.logs, function (logRaw) {
		var flag, lineNumber = isNumber(logRaw[2]) ? logRaw[2] : -1,
			logObj = {},
			type = logRaw[0][0],
			map = logKeyMappping[type];

		forEach(logRaw[0], function (value, index) {
			var key = map[index];

			if (key.charAt(0) === '@') {
				key = key.substr(1);
				flag = key === 'type' ? typeMap[value] : value;
			}
			logObj[key] = value;
		});

		logList.push({
			time: baseTime + logRaw[1],
			line: lineNumber,
			body: logObj,
			flag: flag
		});

		availLineOptions[lineNumber] = true;
	});

	// Divide logList into groups by 'exit' logMark.
	forEach(logRawOpts.marks, function (mark) {
		var assertCount = 0,
			loopLogRaw = logRawOpts.logs.slice(startLogNumber, mark[2] + 1);

		loopState[mark[0]].push(mark[1]);

		forEach(loopLogRaw, function (insLog, index) {
			var key, l = insLog[0];
			if (l[0] === 0x13) {
				key = '#' + assertCount;
				if (performance.hasOwnProperty(key)) {
					performance[key].data.push(logRawOpts.performance[key].shift());
				}
				assertCount += 1;
			}
		});

		forEach(performance, function (pO, key) {
			if (key.substr(1) >= assertCount) {
				pO.data.push(null);
			}
		});

		logGroupByLoop.push(logList.slice(startLogNumber, mark[2] + 1));
		startLogNumber = mark[2] + 1;
	});

	forEach(availLineOptions, function (v, key) {
		availLines.push(parseInt(key, 0));
	});

	forEach(performance, function (pO, key) {
		var min = Number.MAX_VALUE,
			aI = 0, // (a)vail(I)ndex of data.
			max = -1,
			sum = 0;

		forEach(pO.data, function (v) {
			if (v === null) {
				return;
			}
			max = v > max ? v : max;
			min = v < min ? v : min;
			sum += v;
			aI += 1;
		});

		pO.max = max;
		pO.min = min;
		pO.avg = parseInt(sum / aI, 0);
	});

	return {
		resolvedLog: logGroupByLoop,
		performance: performance,
		availLines: availLines,
		loopOption: loopState,
		failureNumber: loopState[map.F].length,
		passedNumber: loopState[map.P].length
	};
};
